import { SquareGrounp } from "./SquareGrounp";
import { createTeris } from "./Teris";
import { TerisRule } from "./TerisRule";
import { GameStatus, GameViewer, MoveDirection } from "./types";
import GamrConfig from './GameConfig'
import { Square } from "./Square";

/**
 * 游戏控制类
 */
export class Game {
  // 游戏状态
  private _gameStatus: GameStatus = GameStatus.init
  // 当前玩家操作的方块
  private _curTeris?: SquareGrounp;
  // 下一个方块
  private _nextTeris: SquareGrounp;
  // 计数器
  private _timer?: number;
  // 自由下落间隔时间
  private _duration?: number; //  游戏越难 时间越小
  // 保存当前游戏中,已经落下的方块
  private _exists: Square[] = []
  // 分数
  private _score: number = 0

  get score() {
    return this._score
  }

  set score(val) {
    this._score = val
    this._viewer.showScore(this._score)
    const { duration } = GamrConfig.levels.filter(it => it.score <= val).pop()!; // ! 去除undefined
    if(this._duration === duration) return
    clearInterval(this._timer)
    this._timer = undefined
    this.autoDrop()
    console.log("难度变化", duration);
    this._duration = duration
  }
  get gameStatus() {
    return this._gameStatus
  }

  constructor(private _viewer: GameViewer) {
    this._nextTeris = createTeris({ x: 0, y: 0 }) // 没有实际含义的代码，只是为了ts不报错
    this.init()
    this._viewer.init(this)
  }

  /**
   * 创建下一个方块
   */
  private craeteNext() {
    // 创建下一个方块
    this._nextTeris = createTeris({ x: 0, y: 0 })
    // 防止下一个方块超出顶部 通过样式移动到面板外面
    this.restCenterPoint(GamrConfig.nextSize.width, this._nextTeris)
    // 显示下一个方块
    this._viewer.showNext(this._nextTeris)
  }

  /**
   * 初始化
   */
  private init() {
    this.score = 0
    this._exists.forEach(sq => sq.viewer?.remove())
    this._exists = []
    this.craeteNext()
    this._curTeris = undefined
  }

  /**
   * 游戏开始
   */
  start() {
    // 游戏状态改变
    if (this._gameStatus === GameStatus.playing) return

    // 游戏结束状态
    if (this._gameStatus === GameStatus.over) {
      this.init()
    }
    this._gameStatus = GameStatus.playing
    // 方块开始运动
    if (!this._curTeris) {
      // 切换方块
      this.switchTeris()
    }
    // 当前方块自由下落
    this.autoDrop()
    this._viewer.onGameStart()
  }

  /**
   * 暂停
   */
  pause() {
    if (this._gameStatus === GameStatus.playing) {
      this._gameStatus = GameStatus.pause
      clearInterval(this._timer)
      this._timer = undefined
      this._viewer.onGamePause()
    }
  }
  /**
   * 向左
   */
  controlLeft() {
    if (this._curTeris && this._gameStatus === GameStatus.playing) {
      TerisRule.move(this._curTeris, MoveDirection.left, this._exists)
    }
  }
  /**
  * 向右
  */
  controlRight() {
    if (this._curTeris && this._gameStatus === GameStatus.playing) {
      TerisRule.move(this._curTeris, MoveDirection.right, this._exists)
    }
  }
  /**
   * 向下
   */
  controlDown() {
    if (this._curTeris && this._gameStatus === GameStatus.playing) {
      TerisRule.moveDirectly(this._curTeris, MoveDirection.down, this._exists)
      // 触底
      this.hitBottom()
    }
  }

  /**
   * 旋转
   */
  controlRotate() {
    if (this._curTeris && this._gameStatus === GameStatus.playing) {
      TerisRule.rotate(this._curTeris, this._exists)
    }
  }

  /**
   * 当前方块自由下落
   */
  private autoDrop() {
    // 已经有了定时器 游戏不是运行中状态
    if (this._timer || this._gameStatus != GameStatus.playing) return
    // 如果报错：setInterval返回类型是 Timer 推断为node的setInterval
    // 删除node环境 node_modules/@types/node
    this._timer = setInterval(() => {
      if (this._curTeris) {
        if (!TerisRule.move(this._curTeris, MoveDirection.down, this._exists)) {
          // 触底
          this.hitBottom()
        }
      }
    }, this._duration)
  }

  /**
   * 切换方块
   */
  private switchTeris() {
    this._curTeris = this._nextTeris
    this.restCenterPoint(GamrConfig.panelSize.width, this._curTeris)

    // 是否可以移动到目前的位置 移动不了
    if (!TerisRule.canIMove(this._curTeris.shape, this._curTeris.centerPoint, this._exists)) {
      this.over()// 游戏结束
      return
    }

    this.craeteNext()

    this._viewer.switch(this._curTeris)
  }

  /**
   * 游戏结束
   */
  private over() {
    this._gameStatus = GameStatus.over
    clearInterval(this._timer)
    this._timer = undefined
    this._curTeris?.squares.forEach(sq => sq.viewer && sq.viewer.remove())
    this._viewer.onGameOver()
  }

  /**
   * 设置中心点坐标，达到让改方块出现在区域的顶部中心，不超出
   * @param width 
   * @param teris 
   */
  private restCenterPoint(width: number, teris: SquareGrounp) {
    const x = Math.floor(width / 2) - 1
    let y = 0
    teris.centerPoint = { x, y }
    // y坐标是否有小于0的，有往下移动
    while (teris.squares.some(it => it.point.y < 0)) {
      // 设置中心点坐标 y+1
      teris.centerPoint = { x: teris.centerPoint.x, y: teris.centerPoint.y + 1 }
    }
  }

  /**
   * 触底之后的操作
   */
  private hitBottom() {
    // 将当前的俄罗斯方块加入到已存在的数组中
    this._exists.push(...this._curTeris!.squares)

    // 消除方块处理 
    const num = TerisRule.deleteSquares(this._exists)

    // 增加积分
    this.addScore(num)

    // 切换方块
    this.switchTeris()

  }

  /**
   * 增加积分 消除一行 一行的格子数分 每多一行多加5分 
   * @param lineNum 
   */
  private addScore(lineNum: number) {
    this.score += lineNum * GamrConfig.panelSize.width + this.getScore(lineNum)
  }

  /**
   * 获取多行的累计分数
   * @param lineNum 
   */
  private getScore(lineNum: number): number {
    if (lineNum <= 1) {
      return 0
    }
    return this.getScore(lineNum - 1) + 5
  }

}